package br.com.wepa.webapps.orca.aspect;

import java.util.Stack;

import javax.persistence.PersistenceException;

import br.com.wepa.webapps.orca.logica.persistencia.transaction.Transaction;
import br.com.wepa.webapps.orca.logica.persistencia.transaction.TransactionManager;


/**
 * @author fabricio.epaminondas
 */
public aspect TransactionContext extends TransactionManager {
	
	
	private static final ThreadLocal<Stack<Integer>> context = new ThreadLocal<Stack<Integer>>();
	
	pointcut transaction() :  execution(@Transaction * *.*(..));
	
	 before() : transaction(){
		try {
			//Init the Transaction if is non active transactions in this context
			if(!isActiveTransaction()){
				super.iniciarTransacao();				
				initContext();				
			}else{
				//Exists one active Thread Local Transaction, doesn't need to init other
				pushContextStack();
			}
		} catch (PersistenceException e) {
			throw new RuntimeException(e);
		}
	}

	 
	after() returning() : transaction() {
		try {	
			//Finalizes the transaction if the context satck is empty
			if(contextStackEmpty()){
				super.finalizaTransacao();	
			}else if(isActiveTransaction()){
				popContextStack();//on returning from transactional methods, pops the satck
			}			
		} catch (PersistenceException e) {
			super.rollBack();
			throw new RuntimeException(e);
		}
	}

	private void popContextStack() {
		context.get().pop();
	}

	private boolean contextStackEmpty() {
		return context.get().isEmpty();
	}
	
	after() throwing() : transaction() {
		try {
			super.rollBack();
		} catch (PersistenceException e) {
			throw new RuntimeException(e);
		}
	}
	
	
	private void pushContextStack() {
		context.get().push(0);
	}

	private void initContext() {
		context.set(new Stack<Integer>());
	}
	

	
}
